home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / security / shadow-3.1.4 / copydir.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-26  |  7.0 KB  |  373 lines

  1. /*
  2.  * Copyright 1991, John F. Haugh II
  3.  * An unpublished work.
  4.  * All rights reserved.
  5.  *
  6.  * Permission is granted to copy and create derivative works for any
  7.  * non-commercial purpose, provided this copyright notice is preserved
  8.  * in all copies of source code, or included in human readable form
  9.  * and conspicuously displayed on all copies of object code or
  10.  * distribution media.
  11.  */
  12.  
  13. #include <sys/types.h>
  14. #include <sys/stat.h>
  15. #include "config.h"
  16. #ifdef DIR_XENIX
  17. #include <sys/ndir.h>
  18. #define DIRECT direct
  19. #endif
  20. #ifdef DIR_BSD
  21. #include <ndir.h>
  22. #define DIRECT direct
  23. #endif
  24. #ifdef DIR_SYSV
  25. #include <dirent.h>
  26. #define DIRECT dirent
  27. #endif
  28. #include <fcntl.h>
  29. #include <stdio.h>
  30.  
  31. #ifndef lint
  32. static    char    sccsid[] = "@(#)copydir.c    3.1    10:09:26    6/13/91";
  33. #endif
  34.  
  35. #ifndef    S_ISDIR
  36. #define    S_ISDIR(x)    (((x)&S_IFMT)==S_IFDIR)
  37. #endif
  38. #ifndef    S_ISREG
  39. #define    S_ISREG(x)    (((x)&S_IFMT)==S_IFREG)
  40. #endif
  41.  
  42. static    char    *src_orig;
  43. static    char    *dst_orig;
  44.  
  45. struct    link_name {
  46.     int    ln_dev;
  47.     int    ln_ino;
  48.     int    ln_count;
  49.     char    *ln_name;
  50.     struct    link_name *ln_next;
  51. };
  52. static    struct    link_name *links;
  53.  
  54. /*
  55.  * remove_link - delete a link from the link list
  56.  */
  57.  
  58. void
  59. remove_link (link)
  60. struct    link_name *link;
  61. {
  62.     struct link_name *lp;
  63.  
  64.     if (links == link) {
  65.         links = link->ln_next;
  66.         free (link->ln_name);
  67.         free (link);
  68.         return;
  69.     }
  70.     for (lp = links;lp;lp = lp->ln_next)
  71.         if (lp->ln_next == link)
  72.             break;
  73.  
  74.     if (! lp)
  75.         return;
  76.  
  77.     lp->ln_next = lp->ln_next->ln_next;
  78.     free (link->ln_name);
  79.     free (link);
  80. }
  81.  
  82. /*
  83.  * check_link - see if a file is really a link
  84.  */
  85.  
  86. struct link_name *
  87. check_link (name, sb)
  88. char    *name;
  89. struct    stat    *sb;
  90. {
  91.     struct    link_name *lp;
  92.     int    src_len;
  93.     int    dst_len;
  94.     int    name_len;
  95.     char    *malloc ();
  96.  
  97.     for (lp = links;lp;lp = lp->ln_next)
  98.         if (lp->ln_dev == sb->st_dev && lp->ln_ino == sb->st_ino)
  99.             return lp;
  100.  
  101.     if (sb->st_nlink == 1)
  102.         return 0;
  103.  
  104.     lp = (struct link_name *) malloc (sizeof *lp);
  105.     src_len = strlen (src_orig);
  106.     dst_len = strlen (dst_orig);
  107.     name_len = strlen (name);
  108.     lp->ln_dev = sb->st_dev;
  109.     lp->ln_ino = sb->st_ino;
  110.     lp->ln_count = sb->st_nlink;
  111.     lp->ln_name = malloc (name_len - src_len + dst_len + 1);
  112.     sprintf (lp->ln_name, "%s%s", dst_orig, name + src_len);
  113.     lp->ln_next = links;
  114.     links = lp;
  115.  
  116.     return 0;
  117. }
  118.  
  119. /*
  120.  * copy_tree - copy files in a directory tree
  121.  *
  122.  *    copy_tree() walks a directory tree and copies ordinary files
  123.  *    as it goes.
  124.  */
  125.  
  126. int
  127. copy_tree (src_root, dst_root, uid, gid)
  128. char    *src_root;
  129. char    *dst_root;
  130. int    uid;
  131. int    gid;
  132. {
  133.     char    src_name[BUFSIZ];
  134.     char    dst_name[BUFSIZ];
  135.     char    buf[BUFSIZ];
  136.     int    ifd;
  137.     int    ofd;
  138.     int    err = 0;
  139.     int    cnt;
  140.     int    set_orig = 0;
  141.     struct    DIRECT    *ent;
  142.     struct    stat    sb;
  143.     struct    link_name *lp;
  144.     DIR    *dir;
  145.  
  146.     /*
  147.      * Make certain both directories exist.  This routine is called
  148.      * after the home directory is created, or recursively after the
  149.      * target is created.  It assumes the target directory exists.
  150.      */
  151.  
  152.     if (access (src_root, 0) != 0 || access (dst_root, 0) != 0)
  153.         return -1;
  154.  
  155.     /*
  156.      * Open the source directory and read each entry.  Every file
  157.      * entry in the directory is copied with the UID and GID set
  158.      * to the provided values.  As an added security feature only
  159.      * regular files (and directories ...) are copied, and no file
  160.      * is made set-ID.
  161.      */
  162.  
  163.     if (! (dir = opendir (src_root)))
  164.         return -1;
  165.  
  166.     if (src_orig == 0) {
  167.         src_orig = src_root;
  168.         dst_orig = dst_root;
  169.         set_orig++;
  170.     }
  171.     while (ent = readdir (dir)) {
  172.  
  173.         /*
  174.          * Skip the "." and ".." entries
  175.          */
  176.  
  177.         if (strcmp (ent->d_name, ".") == 0 ||
  178.                 strcmp (ent->d_name, "..") == 0)
  179.             continue;
  180.  
  181.         /*
  182.          * Make the filename for both the source and the
  183.          * destination files.
  184.          */
  185.  
  186.         if (strlen (src_root) + strlen (ent->d_name) + 2 > BUFSIZ) {
  187.             err++;
  188.             break;
  189.         }
  190.         sprintf (src_name, "%s/%s", src_root, ent->d_name);
  191.  
  192.         if (strlen (dst_root) + strlen (ent->d_name) + 2 > BUFSIZ) {
  193.             err++;
  194.             break;
  195.         }
  196.         sprintf (dst_name, "%s/%s", dst_root, ent->d_name);
  197.  
  198.         if (stat (src_name, &sb) == -1)
  199.             continue;
  200.  
  201.         if (S_ISDIR (sb.st_mode)) {
  202.  
  203.             /*
  204.              * Create a new target directory, make it owned by
  205.              * the user and then recursively copy that directory.
  206.              */
  207.  
  208.             mkdir (dst_name, sb.st_mode & 0777);
  209.             chown (dst_name, uid == -1 ? sb.st_uid:uid,
  210.                 gid == -1 ? sb.st_gid:gid);
  211.  
  212.             if (copy_tree (src_name, dst_name, uid, gid)) {
  213.                 err++;
  214.                 break;
  215.             }
  216.             continue;
  217.         }
  218.  
  219.         /*
  220.          * See if this is a previously copied link
  221.          */
  222.  
  223.         if (lp = check_link (src_name, &sb)) {
  224.             if (link (lp->ln_name, dst_name)) {
  225.                 err++;
  226.                 break;
  227.             }
  228.             if (unlink (src_name)) {
  229.                 err++;
  230.                 break;
  231.             }
  232.             if (--lp->ln_count <= 0)
  233.                 remove_link (lp);
  234.  
  235.             continue;
  236.         }
  237.  
  238.         /*
  239.          * Deal with FIFOs and special files.  The user really
  240.          * shouldn't have any of these, but it seems like it
  241.          * would be nice to copy everything ...
  242.          */
  243.  
  244.         if (! S_ISREG (sb.st_mode)) {
  245.             if (mknod (dst_name, sb.st_mode & ~07777, sb.st_rdev) ||
  246.                 chown (dst_name, uid == -1 ? sb.st_uid:uid,
  247.                     gid == -1 ? sb.st_gid:gid) ||
  248.                     chmod (dst_name, sb.st_mode & 07777)) {
  249.                 err++;
  250.                 break;
  251.             }
  252.             continue;
  253.         }
  254.  
  255.         /*
  256.          * Create the new file and copy the contents.  The new
  257.          * file will be owned by the provided UID and GID values.
  258.          */
  259.  
  260.         if ((ifd = open (src_name, O_RDONLY)) < 0) {
  261.             err++;
  262.             break;
  263.         }
  264.         if ((ofd = open (dst_name, O_WRONLY|O_CREAT, 0)) < 0 ||
  265.             chown (dst_name, uid == -1 ? sb.st_uid:uid,
  266.                     gid == -1 ? sb.st_gid:gid) ||
  267.                 chmod (dst_name, sb.st_mode & 07777)) {
  268.             close (ifd);
  269.             err++;
  270.             break;
  271.         }
  272.         while ((cnt = read (ifd, buf, sizeof buf)) > 0) {
  273.             if (write (ofd, buf, cnt) != cnt) {
  274.                 cnt = -1;
  275.                 break;
  276.             }
  277.         }
  278.         close (ifd);
  279.         close (ofd);
  280.  
  281.         if (cnt == -1) {
  282.             err++;
  283.             break;
  284.         }
  285.     }
  286.     closedir (dir);
  287.  
  288.     if (set_orig) {
  289.         src_orig = 0;
  290.         dst_orig = 0;
  291.     }
  292.     return err ? -1:0;
  293. }
  294.  
  295. /*
  296.  * remove_tree - remove files in a directory tree
  297.  *
  298.  *    remove_tree() walks a directory tree and deletes all the files
  299.  *    and directories.
  300.  */
  301.  
  302. int
  303. remove_tree (root)
  304. char    *root;
  305. {
  306.     char    new_name[BUFSIZ];
  307.     int    err = 0;
  308.     struct    DIRECT    *ent;
  309.     struct    stat    sb;
  310.     DIR    *dir;
  311.  
  312.     /*
  313.      * Make certain the directory exists.
  314.      */
  315.  
  316.     if (access (root, 0) != 0)
  317.         return -1;
  318.  
  319.     /*
  320.      * Open the source directory and read each entry.  Every file
  321.      * entry in the directory is copied with the UID and GID set
  322.      * to the provided values.  As an added security feature only
  323.      * regular files (and directories ...) are copied, and no file
  324.      * is made set-ID.
  325.      */
  326.  
  327.     dir = opendir (root);
  328.  
  329.     while (ent = readdir (dir)) {
  330.  
  331.         /*
  332.          * Skip the "." and ".." entries
  333.          */
  334.  
  335.         if (strcmp (ent->d_name, ".") == 0 ||
  336.                 strcmp (ent->d_name, "..") == 0)
  337.             continue;
  338.  
  339.         /*
  340.          * Make the filename for the current entry.
  341.          */
  342.  
  343.         if (strlen (root) + strlen (ent->d_name) + 2 > BUFSIZ) {
  344.             err++;
  345.             break;
  346.         }
  347.         sprintf (new_name, "%s/%s", root, ent->d_name);
  348.         if (stat (new_name, &sb) == -1)
  349.             continue;
  350.  
  351.         if (S_ISDIR (sb.st_mode)) {
  352.  
  353.             /*
  354.              * Recursively delete this directory.
  355.              */
  356.  
  357.             if (remove_tree (new_name)) {
  358.                 err++;
  359.                 break;
  360.             }
  361.             if (rmdir (new_name)) {
  362.                 err++;
  363.                 break;
  364.             }
  365.             continue;
  366.         }
  367.         unlink (new_name);
  368.     }
  369.     closedir (dir);
  370.  
  371.     return err ? -1:0;
  372. }
  373.